ZooKeeper

我们选择ZooKeeper作为dubbo的注册中心

概述

Apache ZooKeeper是由集群(节点组)使用的一种服务,用于在自身之间协调,并通过稳健的同步技术维护共享数据。ZooKeeper本身是一个分布式应用程序,为写入分布式应用程序提供服务。

ZooKeeper提供的常见服务如下 :

  • 命名服务 - 按名称标识集群中的节点。它类似于DNS,但仅对于节点。
  • 配置管理 - 加入节点的最近的和最新的系统配置信息。
  • 集群管理 - 实时地在集群和节点状态中加入/离开节点。
  • 选举算法 - 选举一个节点作为协调目的的leader。
  • 锁定和同步服务 - 在修改数据的同时锁定数据。此机制可帮助你在连接其他分布式应用程序(如Apache HBase)时进行自动故障恢复。
  • 高度可靠的数据注册表 - 即使在一个或几个节点关闭时也可以获得数据。

分布式应用程序提供了很多好处,但它们也抛出了一些复杂和难以解决的挑战。ZooKeeper框架提供了一个完整的机制来克服所有的挑战。竞争条件和死锁使用故障安全同步方法进行处理。另一个主要缺点是数据的不一致性,ZooKeeper使用原子性解析。

以下是使用ZooKeeper的好处:

  • 简单的分布式协调过程
  • 同步 - 服务器进程之间的相互排斥和协作。此过程有助于Apache HBase进行配置管理。
  • 有序的消息
  • 序列化 - 根据特定规则对数据进行编码。确保应用程序运行一致。这种方法可以在MapReduce中用来协调队列以执行运行的线程。
  • 可靠性
  • 原子性 - 数据转移完全成功或完全失败,但没有事务是部分的。

安装

我们将在linux服务器上部署配置单机zk,请先确认已安装Java。

  1. https://www.apache.org/dyn/closer.cgi/zookeeper/,官网下载最新版本。本文下载的是zookeeper-3.4.10.tar.gz。
1
2
cd ~
wget http://mirrors.shu.edu.cn/apache/zookeeper/stable/zookeeper-3.4.10.tar.gz
  1. 提取tar文件
1
2
tar -zxvf zookeeper-3.4.10.tar.gz
cd zookeeper-3.4.10
  1. 创建配置文件
1
2
mkdir data/zookeeper
vim conf/zoo.cfg

输入以下内容

1
2
3
4
5
tickTime = 2000
dataDir = /data/zookeeper
clientPort = 2181
initLimit = 5
syncLimit = 2
  1. 启动zk
1
bin/zkServer.sh start

你会看到以下输出

1
2
3
ZooKeeper JMX enabled by default
Using config: /root/zookeeper-3.4.10/bin/../conf/zoo.cfg
Starting zookeeper ... STARTED
  1. 启动CLI
1
bin/zkCli.sh

输入上面这个命令,将连接到zk服务器,你会看到如下输出:

1
2
3
4
5
6
7
Connecting to localhost:2181
...
Welcome to ZooKeeper!
...
WATCHER::
WatchedEvent state:SyncConnected type:None path:null
[zk: localhost:2181(CONNECTED) 0]

输入quit退出CLI

CLI相关操作可以参考https://www.w3cschool.cn/zookeeper/zookeeper_cli.html

整合dubbo

首先,我们需要新建两个module,dubbo-api、dubbo-provider。

dubbo-api:用来定义提供rpc调用的接口和实体类。

dubbo-provider:是一个web项目,作为rpc服务的提供者,实现dubbo-api里定义的接口。

dubbo-api

新建module结果如下:

jiegou10

DemoFacade做为向外提供的接口:

1
2
3
public interface DemoFacade {
Integer safeAdd(Integer a, Integer b);
}

pom.xml:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>demo</artifactId>
<groupId>com.tt.study</groupId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<packaging>jar</packaging>
<artifactId>dubbo-api</artifactId>

</project>

dubbo-provider

作为一个新的Spring Boot Web项目,结构如下:

jiegou11

pom.xml:我们需要引入刚刚创建的dubbo-api依赖,由于spring官方还没有出dubbo-starter,所有这里我们自己手动引入dubbo相关依赖,这里我们使用curator-client而不是默认的zkclient。注意,我这边的dubbo版本是2.6.1,只能使用版本3.0以下的curator,使用3.0以上的会报错。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>demo</artifactId>
<groupId>com.tt.study</groupId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<packaging>jar</packaging>
<artifactId>dubbo-provider</artifactId>

<dependencies>
<dependency>
<groupId>com.tt.study</groupId>
<artifactId>dubbo-api</artifactId>
</dependency>
<!-- spring boot -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- dubbo -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>dubbo</artifactId>
<version>${dubbo.version}</version>
<exclusions>
<exclusion>
<artifactId>spring-context</artifactId>
<groupId>org.springframework</groupId>
</exclusion>
</exclusions>
</dependency>
<!-- dubbo client -->
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>2.12.0</version>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>

application.yml:只修改了下端口

1
2
server:
port: 8081

DubboProviderApplication:没有其他修改

1
2
3
4
5
6
@SpringBootApplication
public class DubboProviderApplication {
public static void main(String[] args) {
SpringApplication.run(DubboProviderApplication.class, args);
}
}

DemoFacadeImpl:作为api中DemoFacade的实现类,这里我们使用的是dubbo提供的@Service注解

1
2
3
4
5
6
7
8
9
10
11
12
13
@com.alibaba.dubbo.config.annotation.Service(timeout = 5000)
public class DemoFacadeImpl implements DemoFacade {
@Override
public Integer safeAdd(Integer a, Integer b) {
if (a == null) {
a = 0;
}
if (b == null) {
return a;
}
return a + b;
}
}

DubboConfig:关键的dubbo配置类。更多配置可以参考dubbo用户手册

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@Configuration
//扫描dubbo相关注解
@DubboComponentScan("com.tt.study.dubbo.provider")
public class DubboConfig {
@Bean
public ApplicationConfig applicationConfig(){
ApplicationConfig applicationConfig = new ApplicationConfig();
applicationConfig.setName("dubbo-provider");
return applicationConfig;
}
@Bean
public RegistryConfig registryConfig(){
RegistryConfig registryConfig = new RegistryConfig();
//协议使用zk
registryConfig.setProtocol("zookeeper");
//zk地址
registryConfig.setAddress("118.126.82.20:2181");
//client
registryConfig.setClient("curator");
return registryConfig;
}
}

调用接口

我们在原来的web模块中,调用dubbo-provider提供的服务。

pom.xml:添加以下依赖

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<!-- dubbo -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>dubbo</artifactId>
<version>${dubbo.version}</version>
<exclusions>
<exclusion>
<artifactId>spring-context</artifactId>
<groupId>org.springframework</groupId>
</exclusion>
</exclusions>
</dependency>
<!-- dubbo client -->
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>2.12.0</version>
</dependency>
<!-- dubbo provider api -->
<dependency>
<groupId>com.tt.study</groupId>
<artifactId>dubbo-api</artifactId>
</dependency>

新增DubboConfig:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
@Configuration
@DubboComponentScan(basePackages = "com.tt.study.demo")
public class DubboConfig {
@Bean
public ApplicationConfig applicationConfig(){
ApplicationConfig applicationConfig = new ApplicationConfig();
applicationConfig.setName("dubbo-consumer");
return applicationConfig;
}

@Bean
public ConsumerConfig consumerConfig(){
ConsumerConfig consumerConfig = new ConsumerConfig();
consumerConfig.setTimeout(3000);
return consumerConfig;
}

@Bean
public RegistryConfig registryConfig(){
RegistryConfig registryConfig = new RegistryConfig();
registryConfig.setProtocol("zookeeper");
registryConfig.setAddress("118.126.82.20:2181");
registryConfig.setClient("curator");
return registryConfig;
}
}

现在,我们可以在service中直接使用@com.alibaba.dubbo.config.annotation.Reference注解注入接口,像其他service一样调用:

1
2
3
4
5
6
7
@Reference
private DemoFacade demoFacade;

public void safeAdd(Integer a, Integer b){
Integer sum = demoFacade.safeAdd(a, b);
log.info("safeAdd sum = {}", sum);
}

Ok,基础的rpc调用完成了。

本节代码